﻿using AutoMapper;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Windows.Admin.Application.Service;
using Windows.Admin.Contract;
using Windows.Admin.Domain;
using Windows.Admin.Infrastructure.EFCore;
using Windows.Admin.Infrastructure.EFCore.Extensions;
using Windows.Application.Share;
using Windows.FileStorage.Contract;
using Windows.Infrastructure.Share.Extensions;
using Windows.Infrastructure.Share.Security;
using Windows.Infrastructure.Share.Tools;
using Windows.SeedWord;

namespace Windows.Admin.Application
{
    public class EmployeeService : IEmployeeService
    {
        private readonly IMapper _mapper;
        //private readonly ICache _cache;
        private readonly AdminDbContext _db;
        private readonly IAttachmentGrpcService _attachmentGrpcSvc;
        public EmployeeService(IMapper mapper, AdminDbContext db, IAttachmentGrpcService attachmentGrpcSvc)
        {
            _mapper = mapper;
            _db = db;
            _attachmentGrpcSvc = attachmentGrpcSvc;
        }
        /// <summary>
        /// 员工视图
        /// </summary>
        /// <param name="info"></param>
        /// <param name="isEnable"></param>
        /// <returns></returns>
        public async Task<PageResponse<EmployeeResponse>> Query(PageRequest<EmployeeRequest> request)
        {
            var response = new PageResponse<EmployeeResponse>();
            IQueryable<Employee> query = _db.Employee.Include(x => x.User).Include(x => x.Organization_Employees);
            var organizations = await _db.Organization.ToListAsync();
            if (request.Query.OrganizationId != null)
            {
                List<long> ids = new ();
                GetCurrentAndChildrenIds(organizations, ids, request.Query.OrganizationId.Value, true);
                query = query.GetByOrganizationIds(ids.ToArray());
            }
            if (request.Query.Number != null)
            {
                query = query.Where(x => x.Number.Contains(request.Query.Number));
            }
            if (request.Query.IDCard != null)
            {
                query = query.Where(x => x.IDCard.Contains(request.Query.IDCard));
            }
            if (request.Query.Name != null)
            {
                query = query.Where(x => x.Name.Contains(request.Query.Name));
            }
            if (request.Query.Education != null)
            {
                query = query.Where(x => x.Education == request.Query.Education);
            }
            if (request.Query.Status != null)
            {
                query = query.Where(x => x.Status == request.Query.Status);
            }
            if (request.Query.MobilePhone != null)
            {
                query = query.Where(x => x.Number.Contains(request.Query.MobilePhone));
            }
            if (request.Query.HireDateBegin != null)
            {
                query = query.Where(x => x.HireDate>= request.Query.HireDateBegin);
            }
            if (request.Query.HireDateEnd != null)
            {
                query = query.Where(x => x.HireDate<=request.Query.HireDateEnd);
            }

            var list = await query.Paging(request.PageIndex, request.PageSize).ToListAsync();
            var employeesDtos = _mapper.Map<List<EmployeeResponse>>(list);
            GetAttachmentsByOwnerIdsRequest grpcrequest = new()
            {
                OwnerIds = employeesDtos.Select(s => s.Id).ToList()
            };
            if (grpcrequest.OwnerIds.Count > 0)
            {
                var attachements = await _attachmentGrpcSvc.GetAttachmentsByOwnerIds(grpcrequest);
                foreach (var l in employeesDtos)
                {
                    l.AttachmentPath = attachements.Where(x => x.OwnerId == l.Id).Select(s => s.AttachmentPath).FirstOrDefault();

                    if (l.OrganizationIds == null)
                        continue;
                    foreach (var organizationId in l.OrganizationIds)
                    {
                        string organizationName = "";
                        List<Organization> outList = new();
                        Organization? organization = organizations.FirstOrDefault(x => x.Id == organizationId);
                        if (organization != null)
                        {
                            GetCurrentAndParents(organizations, outList, organization!);
                            foreach (var obj in outList)
                            {
                                organizationName = obj.Name + "-" + organizationName;
                            }
                            if (organizationName.Length > 0)
                                l.OrganizationNames.Add(organizationName.Trim('-'));
                        }
                    }
                }
            }
            response.TotalCount = await query.CountAsync();
            response.PageIndex = request.PageIndex;
            response.PageSize = request.PageSize;
            response.List = employeesDtos;
            return response;
        }
        /// <summary>
        /// 获取id的员工详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<EmployeeResponse> Detail(int id)
        {
            var model = await _db.Employee.Include(x => x.User).Include(x => x.Organization_Employees).FindByIdAsync(id);
            var response = _mapper.Map<EmployeeResponse>(model);
            AttachmentRequest request = new() 
            {
                OwnerId = model.Id
            };
            var attaResponse = await _attachmentGrpcSvc.GetAttachment(request);
            if(!attaResponse.AttachmentPath.IsNullOrEmpty())
                response.AttachmentPath = attaResponse.AttachmentPath;
            return response;
            
        }
        /// <summary>
        /// 员工保存
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        /// <exception cref="ApiException"></exception>
        public async Task Save(EmployeeSaveRequest request)
        {
            if (_db.Employee.Count(x => x.Number.ToLower() == request.Number && x.Id != request.Id) > 0)
                throw new ApiException("员工编号已存在!");
            if (request.UserId != null)
            {
                if (_db.User.Count(x => x.Id == request.UserId) <= 0)
                    throw new ApiException("用户不存在!");
            }
            Employee? model = new();
            if (request.Id == null)
            {
                using var tran = _db.Database.BeginTransaction();
                try
                {
                    model = _mapper.Map<Employee>(request);
                    model.UserId = request.Id;
                    await _db.Employee.AddAsync(model);
                    await _db.SaveChangesAsync();

                    List<Organization_Employee> organization_Employees = new();
                    foreach (var organizationId in request.OrganizationIds)
                    {
                        Organization_Employee organization_Employee = new()
                        {
                            EmployeeId = model.Id,
                            OrganizationId = organizationId
                        };
                        organization_Employees.Add(organization_Employee);
                    }
                    await _db.Organization_Employee.AddRangeAsync(organization_Employees);

                    await _db.SaveChangesAsync();
                    await tran.CommitAsync();
                }
                catch (Exception)
                {
                    await tran.RollbackAsync();
                    throw;
                }
            }
            else
            {
                using var tran = _db.Database.BeginTransaction();
                try
                {
                    model = await _db.Employee.FindByIdAsync(request.Id.Value);
                    if (model == null)
                        throw new ApiException("员工不存在!");
                    model.UserId = request.Id;
                    model.Number = request.Number;
                    model.Name = request.Name;
                    model.IDCard = request.IDCard;
                    model.Gender = request.Gender;
                    model.Marriage = request.Marriage;
                    model.Education = request.Education;
                    model.MobilePhone = request.MobilePhone;
                    model.Email = request.Email;
                    model.Address = request.Address;
                    model.HireDate = request.HireDate;
                    model.TermDate = request.TermDate;
                    model.Status = request.Status;
                    model.Avatar = request.Avatar;
                    model.Remark = request.Remark;

                    List<Organization_Employee> oes = await _db.Organization_Employee.Where(x => x.EmployeeId == request.Id.Value).ToListAsync();
                    _db.Organization_Employee.RemoveRange(oes);

                    List<Organization_Employee> organization_Employees = new();
                    foreach (var organizationId in request.OrganizationIds)
                    {
                        Organization_Employee organization_Employee = new()
                        {
                            EmployeeId = model.Id,
                            OrganizationId = organizationId
                        };
                        organization_Employees.Add(organization_Employee);
                    }
                    await _db.Organization_Employee.AddRangeAsync(organization_Employees);

                    await _db.SaveChangesAsync();
                    await tran.CommitAsync();
                }
                catch (Exception)
                {
                    await tran.RollbackAsync();
                    throw;
                }
            }
            if (request.AttachmentId != null)
            {
                AttachmentRequest attachmentRequest = new()
                {
                    OwnerId = model.Id,
                    AttachmentId = request.AttachmentId,
                };
                await _attachmentGrpcSvc.SaveAttachment(attachmentRequest);
            }
        }

        /// <summary>
        /// 获取聊天界面的员工列表
        /// </summary>
        /// <returns></returns>
        //[Caching]
        public async Task<List<ChatEmployeeTreeResponse>> GetChatEmployees()
        {
            var employees = await _db.Employee.Include(x => x.User).Include(x => x.Organization_Employees).ToListAsync();
            var organizations = await _db.Organization.ToListAsync();
            var employeesDtos = _mapper.Map<List<ChatEmployeeResponse>>(employees);

            GetAttachmentsByOwnerIdsRequest request = new()
            {
                OwnerIds = employeesDtos.Select(s => s.Id).ToList()
            };

            var attachements = await _attachmentGrpcSvc.GetAttachmentsByOwnerIds(request);

            foreach (var l in employeesDtos)
            {
                l.AttachmentPath = attachements.Where(x => x.OwnerId == l.Id).Select(s => s.AttachmentPath).FirstOrDefault();

                if (l.OrganizationIds == null)
                    continue;
                foreach (var organizationId in l.OrganizationIds)
                {
                    string organizationName = "";
                    List<Organization> outList = new();
                    Organization? organization = organizations.FirstOrDefault(x => x.Id == organizationId);
                    if (organization == null)
                    {
                        GetCurrentAndParents(organizations, outList, organization!);
                        foreach (var obj in outList)
                        {
                            organizationName = obj.Name + "-" + organizationName;
                        }
                        if (organizationName.Length > 0)
                            l.OrganizationNames.Add(organizationName.Trim('-'));
                    }
                }
            }
            return BuildModuleTree(organizations, employeesDtos, null);
        }
        /// <summary>
        /// 获取当前Id及下面节点的Id
        /// </summary>
        /// <param name="list"></param>
        /// <param name="ids"></param>
        /// <param name="id"></param>
        /// <param name="isFirst"></param>
        protected void GetCurrentAndChildrenIds(List<Organization> list, List<long> ids, long id, bool isFirst = false)
        {
            if (isFirst)
                ids.Add(id);
            var childrens = list.Where(x => x.PId == id).Select(s => s.Id).ToList();
            if (childrens.Count > 0)
            {
                ids.AddRange(childrens);
                foreach (int cId in childrens)
                {
                    GetCurrentAndChildrenIds(list, ids, cId);
                }
            }
        }
        /// <summary>
        /// 获取当前Id及父节点的Id
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="outList"></param>
        /// <param name="t"></param>
        protected void GetCurrentAndParents(List<Organization> list, List<Organization> outList, Organization t)
        {
            outList.Add(t);
            var parent = list.FirstOrDefault(x => Equals(x.Id, t.PId));
            if (parent != null)
            {
                GetCurrentAndParents(list, outList, parent);
            }
        }
        protected List<ChatEmployeeTreeResponse> BuildModuleTree(List<Organization> organizations, List<ChatEmployeeResponse> employeesDtos, long? pId)
        {
            List<ChatEmployeeTreeResponse> list = (from d in organizations
                                                       where d.PId == pId
                                                       orderby d.Sort
                                                       select d into x
                                                       select new ChatEmployeeTreeResponse
                                                       {
                                                           Id = x.Id,
                                                           PId = x.PId,
                                                           Type = x.Type,
                                                           Name = x.Name,
                                                           Children = BuildModuleTree(organizations, employeesDtos, x.Id),
                                                           Employees = employeesDtos.Where(o => o.OrganizationIds != null && o.OrganizationIds.Contains(x.Id)).ToList()
                                                       }).ToList();
            return list;
        }
    }
}
